﻿using System;
using System.Web;
using JUtil;
using System.IO;
using System.Text;

/// <summary>
/// JSONP_HttpModule 的摘要描述
/// </summary>
public class JSONP_HttpModule : IHttpModule
{
    private const string JSON_CONTENT_TYPE = "application/json; charset=utf-8";

    #region IHttpModule members

    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(OnBeginRequest);
        context.ReleaseRequestState += new EventHandler(OnReleaseRequestState);
    }

    void OnReleaseRequestState(object sender, EventArgs e)
    {
        HttpApplication httpApplication = (HttpApplication)sender;
        HttpRequest request = httpApplication.Context.Request;
        if (request.ContentType != JSON_CONTENT_TYPE) return;

        HttpResponse response = httpApplication.Response;
        HttpContext context = httpApplication.Context;
        response.Filter = new JsonResponseFilter(response.Filter, context);
    }

    private void OnBeginRequest(object sender, EventArgs e)
    {
        HttpApplication httpApplication = (HttpApplication)sender;
        HttpRequest request = httpApplication.Context.Request;

        if (!IsWebService(request)) return;
        //if (!DataTypeIsJSONP(request)) return;
        request.ContentType = JSON_CONTENT_TYPE;
    }

    private bool DataTypeIsJSONP(HttpRequest request)
    {
        string dataType = request.QueryString.Get("dataType");
        return dataType.Equals("json");
    }

    private bool IsWebService(HttpRequest request)
    {
        return request.Url.AbsolutePath.Contains(".asmx");
    }

    #endregion

    class JsonResponseFilter : Stream
    {
        private readonly Stream responseStream;
        private readonly HttpContext context;

        public JsonResponseFilter(Stream responseStream, HttpContext context)
        {
            this.responseStream = responseStream;
            this.context = context;
        }

        public override bool CanRead { get { return true; } }
        public override bool CanSeek { get { return true; } }
        public override bool CanWrite { get { return true; } }
        public override long Length { get { return 0; } }
        public override long Position { get; set; }

        public override void Close() { responseStream.Close(); }
        public override void Flush() { responseStream.Flush(); }
        public override long Seek(long offset, SeekOrigin origin) { return responseStream.Seek(offset, origin); }
        public override void SetLength(long length) { responseStream.SetLength(length); }
        public override int Read(byte[] buffer, int offset, int count) { return responseStream.Read(buffer, offset, count); }

        public override void Write(byte[] buffer, int offset, int count)
        {
            string strBuffer = Encoding.UTF8.GetString(buffer, offset, count);
            strBuffer = AppendJsonpCallback(strBuffer, context.Request);
            
            byte[] data = Encoding.UTF8.GetBytes(strBuffer);
            responseStream.Write(data, 0, data.Length);
        }

        private string AppendJsonpCallback(string strBuffer, HttpRequest request)
        {
            return request.Params["callback"] + "(" + strBuffer + ");";
        }
    }
}

